import { useEffect, useState } from 'react';
import SockJS from 'sockjs-client';
import Stomp from 'stompjs';
import { getToken } from '@/zero/utils/token';

/**
 * WebSocket Client
 *
 * transports: "", "websocket", "xdr-streaming", "xhr-streaming", "eventsource", "iframe-eventsource", "htmlfile", "iframe-htmlfile", "xdr-polling", "xhr-polling", "iframe-xhr-polling", "jsonp-polling"
 */
const Index = props => {
  const {
    url,
    options = { transports: ['xhr-polling'] },
    connect = {},
    observers = [],
    disconnect = {},
    children,
    autoReconnect = true,
  } = props;

  const newUrl = url.includes('?') ? url : `${url}?token=${getToken()}`;

  const [client, setClient] = useState(null);

  const reconnect = (count = 1) => {
    const newClient = Stomp.over(new SockJS(newUrl, null, options));
    newClient.debug = () => {};

    const { onOpen, onError } = connect;

    newClient.connect(
      connect.headers || {},
      () => {
        if (onOpen) {
          onOpen();
        } else {
          console.log('CONNECTED');
        }

        setClient(newClient);
      },
      error => {
        if (onError) {
          onError();
        } else {
          console.log('ERROR', error);
        }

        if (autoReconnect) {
          if (count < 10) {
            setTimeout(() => {
              reconnect(count + 1);
            }, 10000 * count); // 10秒 * count
          }
        }
      },
    );

    return newClient;
  };

  useEffect(() => {
    const newClient = reconnect();

    return () => {
      if (newClient.ws.readyState === SockJS.OPEN) {
        const { onClose } = disconnect;
        newClient.disconnect(() => {
          if (onClose) {
            onClose();
          }
        }, disconnect.headers);
      }
    };
  }, []);

  useEffect(() => {
    if (client) {
      observers.forEach(observer => {
        const { destination, onMessage } = observer;
        if (destination) {
          client.subscribe(
            destination,
            data => {
              try {
                onMessage(JSON.parse(data.body));
              } catch (e) {
                onMessage(data.body);
              }
            },
            observer.headers,
          );
        }
      });
    }
    return () => {
      if (client) {
        Object.keys(client.subscriptions).forEach(item => {
          client.unsubscribe(item);
        });
      }
    };
  }, [!!client, observers.map(item => item.destination).join(',')]);

  return typeof children === 'function' ? children(client) : children || null;
};

Index.displayName = 'WsClient';
export default Index;
